<template>
  <button
      :class="buttonClass"
      :disabled="disabled || isCopying"
      @click="handleCopy"
      aria-label="Copy to clipboard"
  >
    {{ showSuccess ? successText : buttonText }}
  </button>
</template>

<script setup>
import { ref, computed } from 'vue'

const props = defineProps({
  content: String,
  contentSource: Function,
  buttonText: {
    type: String,
    default: 'Copy to Clipboard'
  },
  buttonClass: [String, Array, Object],
  disabled: Boolean,
  successText: {
    type: String,
    default: 'Copied!'
  },
  successDuration: {
    type: Number,
    default: 2000
  },
  fallback: Boolean
})

const emit = defineEmits(['copy-success', 'copy-fail'])

const showSuccess = ref(false)
const isCopying = ref(false)

const actualContent = computed(() => {
  return props.contentSource ? props.contentSource() : props.content
})

const showFeedback = () => {
  showSuccess.value = true
  setTimeout(() => {
    showSuccess.value = false
  }, props.successDuration)
}

const fallbackCopy = text => {
  const textArea = document.createElement('textarea')
  textArea.value = text
  textArea.style.position = 'fixed'
  textArea.style.left = '-999999px'
  textArea.style.top = '-999999px'
  document.body.appendChild(textArea)
  textArea.focus()
  textArea.select()

  try {
    document.execCommand('copy')
    emit('copy-success', text)
    showFeedback()
  } catch (err) {
    emit('copy-fail', err)
  } finally {
    document.body.removeChild(textArea)
  }
}

const handleCopy = async () => {
  if (!actualContent.value) {
    emit('copy-fail', new Error('No content to copy'))
    return
  }

  isCopying.value = true
  const text = typeof actualContent.value === 'string'
      ? actualContent.value
      : await actualContent.value

  try {
    if (navigator.clipboard) {
      await navigator.clipboard.writeText(text)
      emit('copy-success', text)
      showFeedback()
    } else if (props.fallback) {
      fallbackCopy(text)
    } else {
      throw new Error('Clipboard API not supported')
    }
  } catch (err) {
    emit('copy-fail', err)
  } finally {
    isCopying.value = false
  }
}
</script>